<?php
/**
 * SystemConfig
 */
class System_Model_Config extends Promotor_Model_Abstract {
	
	/**
	 * @var string
	 */
	const XML = 'xml';
	const PHP = 'php';
	const INI = 'ini';

	/**
	 * @var bool
	 */
	protected $_skipExtends = true;
	
	/**
	 * @param bool $flag
	 * @return bool
	 */
	public function setSkipExtends($flag = true) {
		$this->_skipExtends = (bool) $flag;
	}
	
	/**
	 * @return bool
	 */
	public function getSkipExtends() {
		return $this->_skipExtends;
	}

	/**
	 * @var string
	 */
	protected $_moduleName;
	
	/**
	 * @param string $moduleName
	 * @return string
	 */
	public function setModuleName($moduleName) {
		$this->_moduleName = (string) $moduleName;
	}
	
	/**
	 * @return string
	 */
	public function getModuleName() {
		return $this->_moduleName;
	}

	/**
	 * @return bool
	 */
	public function isModule() {
		return null !== $this->_moduleName;
	}
	
	/**
	 * @var string
	 */
	protected $_filename;
	
	/**
	 * @param string $filename
	 * @return string
	 */
	public function setFilename($filename) {
		$this->_filename = (string) $filename;
	}
	
	/**
	 * @return string
	 */
	public function getFilename() {
		return $this->_filename;
	}

	/**
	 * @return string
	 */
	public function getFilepath() {
		$paths = $this->getPathnames();
		if ($this->isModule()) {
			$moduleName = $this->getModuleName();
			if (!isset($paths[$moduleName])) {
				$this->_setStatus(self::FAILURE);
				$this->_addMessage(sprintf('Module config "$s"  do not exsists!',$moduleName));
				return;
			}
			$paths = $paths[$moduleName];
			$key = $this->_getModuleConfigKey($moduleName, $this->getFilename());
		} else {
			$key = $this->getFilename();
		}

		if (!isset($paths[$key])) {
			$this->_setStatus(self::FAILURE);
			$this->_addMessage(sprintf('File "%s" do not exsists!', $key));
			return;
		}
		
		return $paths[$key];
	}
	
	/**
	 * @return Zend_Config
	 */
	public function getConfig() {
		$filepath = $this->getFilepath();

		$options = array(
			'skipExtends'		 => $this->getSkipExtends(),
			'allowModifications' => true
		);
		try {
			$type = $this->_getType($filepath);
			switch ($type) {
				default:
				case self::INI: $config = new Zend_Config_Ini($filepath, null, $options); break;
				case self::XML: $config = new Zend_Config_Xml($filepath, null, $options); break;
				case self::PHP: $config = new Zend_Config(include $filepath, $options); break;
			}
			$this->_setStatus(self::SUCCESS);
		} catch (Zend_Config_Exception $e) {
			$this->_setStatus(self::FAILURE);
			$this->_addException($e);
			return;
		}
		
		return $config;
	}

	/**
	 * @param string $filename
	 * @param string $module
	 * @return Settings_Form_Config
	 */
	public function getForm() {
		$config = $this->getConfig();
		return ($config instanceof Zend_Config)
			? new System_Form_Config($config)
			: null;
	}
	
	/**
	 * @param string $path
	 * @param string $type
	 * @return string
	 */
	protected function _getType($path, $type = null) {
		$type = (null === $type)
			? pathinfo($path, PATHINFO_EXTENSION)
			: $type;

		return strtolower($type);
	}

	/**
	 * @var string
	 */
	protected $_configAppPath = null;

	/**
	 * @param string $path
	 */
	public function setApplicationConfigPath($path) {
		if (!is_dir($path)) {
			throw new System_Model_Config_Exception(sprintf('Directory "%s" do not exsists!', $path));
		}
		$this->_configAppPath = (string) $path;
	}

	/**
	 * Zwraca sciezke do katalogu konfiguracji applikacji
	 * @return string
	 */
	public function getApplicationConfigPath() {
		if (null === $this->_configAppPath) {
			$this->_configAppPath = APP_CONFIGURATION_PATHNAME;
		}
		return $this->_configAppPath;
	}

	/**
	 * @var string
	 */
	protected $_modulesPath = null;
	
	/**
	 * Zwraca sciezke do katalogu z modułami
	 * @param string $path
	 */
	public function setModulesPath($path) {
		if (!is_dir($path)) {
			throw new System_Model_Config_Exception(sprintf('Directory "%s" do not exsists!', $path));
		}
		$this->_modulesPath = (string) $path;
	}

	/**
	 * Zwraca sciezke do katalogu z modułami
	 * @param string $moduleName
	 * @return string
	 */
	public function getModulesPath($moduleName = null) {
		if (null === $this->_modulesPath) {
			$this->_modulesPath = APP_MODULES_PATHNAME;
		}

		$return = $this->_modulesPath;

		if (null !== $moduleName) {
			$return .= "/$moduleName";
		}
		return $return;
	}

	/**
	 * @param string $module
	 * @return string
	 */
	public function getModuleConfigPath($module) {
		return $this->getModulesPath($module) . DIRECTORY_SEPARATOR . APP_CONFIGURATION_DIRNAME;
	}
	
	/**
	 * @param string $module
	 * @param string $filename
	 * @return string
	 */
	protected function _getModuleConfigKey($module, $filename) {
		return basename($module) . '_' . basename($filename);
	}

	/**
	 * @param string $key
	 * @return void
	 */
	public function setModuleFilenameFromKey($key) {
		if (false !== strstr($key,'_')) {
			list($moduleName, $filename) = explode('_', $key);
			$this->setModuleName($moduleName);
			$this->setFilename($filename);
		}
	}
	
	/**
	 * @return array
	 */
	public function getPathnames() {
		return $this->isModule()
			? $this->getModulesPathnames()
			: $this->getApplicationPathnames();
	}

	/**
	 * @var array
	 */
	protected $_applicationPathnames = null;
	
	/**
	 * @return array
	 */
	public function getApplicationPathnames() {
		if (null === $this->_applicationPathnames) {
			$this->_applicationPathnames = array();
			$path = $this->getApplicationConfigPath();
			$directory = new DirectoryIterator($path);
			foreach ($directory as $file) {
				if ($file->isFile() && $file->isReadable() && $file->isWritable()) {
					$this->_applicationPathnames[$file->getFilename()] = $file->getPathname();
				}
			}
		}
		return $this->_applicationPathnames;
	}

	/**
	 * @var array
	 */
	protected $_appModulesConfigPathnames = null;
	
	/**
	 * Zwtaca tablicę plików nazw konfiguracyjnych
	 * 
	 * Zwraca tablice z wszystkimi plikami konfiuracyjnymi systemu
	 *
	 * @return array
	 */
	public function getModulesPathnames() {
		if (null === $this->_appModulesConfigPathnames) {
			$this->_appModulesConfigPathnames = array();

			$path = $this->getModulesPath();
			$modules = new DirectoryIterator($path);
			foreach ($modules as $module) {
				// tylko katalogi z modulami
				if ($module->isDir() && !$module->isDot()) {
					$path  = $module->getPathname();
					$path .= DIRECTORY_SEPARATOR . APP_CONFIGURATION_DIRNAME;

					try {
						// szukamy teraz konfiguracji
						$configuration = new DirectoryIterator($path);
					} catch (RuntimeException $e) {
						continue;
					}
					
					$moduleName = $module->getFilename();
					$this->_appModulesConfigPathnames[$moduleName] = array();

					foreach ($configuration as $config) {
						if ($config->isFile() && $config->isReadable() && $config->isWritable()) {
							$key = $this->_getModuleConfigKey($moduleName, $config->getFilename());
							$this->_appModulesConfigPathnames[$moduleName][$key] = $config->getPathname();
						}
					}
				}
			}
		}
		return $this->_appModulesConfigPathnames;
	}
	
	
	/**
	 * @param Zend_Config|array $data
	 * @return void
	 */
	public function save($data) {
		if (is_array($data)) {
			$data = new Zend_Config($data);
		} else
		if (!$data instanceof Zend_Config) {
			$this->_setStatus(self::FAILURE);
			$this->_addMessage('Data not instanceof Zend_Config');
			return;
		}
		
		$filepath = $this->getFilepath();
		$this->_save($data, $filepath);
	}
	
	/**
	 * @param Zend_Config $config
	 * @param string $path
	 * @param string $type
	 * @return void
	 */
	protected function _save(Zend_Config $config, $path, $type = null) {
		$type = $this->_getType($path, $type);

		switch ($type) {
			default:
			case self::INI: $writer = new Zend_Config_Writer_Ini(); break;
			case self::XML: $writer = new Zend_Config_Writer_Xml(); break;
			case self::PHP: $writer = new Zend_Config_Writer_Array(); break;
		}

		$writer->setConfig($config);
		
		try {
			$writer->write($path);
			$this->_setStatus(self::SUCCESS);
		} catch (Zend_Cache_Exception $e) {
			$this->_setStatus(self::FAILURE);
			$this->_addException($e);
		}
	}	
}